<!--
 * 滑块验证码组件
 * 基于FirstUI的滑块验证组件和自定义的滑块验证码生成工具
 * 适配移动端
 -->
<template>
  <view class="s-slider-captcha">
    <!-- FirstUI滑块验证组件 -->
    <fui-puzzle-verify 
      :width="width" 
      :height="height" 
      :src="bgImage  || captchaData?.bgImage || ''" 
      :cutSrc="sliderImage ||  captchaData?.sliderImage  || ''" 
      :x="0" 
      :y="captchaData?.position?.y || sliderY" 
      @init="initVerify" 
      @verify="verifySlider" 
      ref="puzzleVerifyRef">
    </fui-puzzle-verify>

    <!-- <image :src="captchaData?.bgImage || ''" mode="widthFix" :style="{width: width + 'px', height: height + 'px'}"></image>
    <image :src="captchaData?.sliderImage || ''" mode="widthFix" :style="{width: width + 'px', height: height + 'px'}"></image>
     -->
    <!-- 隐藏的canvas元素，用于生成滑块验证码 -->
    <canvas canvas-id="bgCanvas" :style="{width: width + 'px', height: height + 'px', position: 'absolute', left: '-9999px'}"></canvas>
    <canvas canvas-id="sliderCanvas" :style="{width: width + 'px', height: height + 'px', position: 'absolute', left: '-9999px'}"></canvas>
    <canvas canvas-id="cutCanvas" :style="{width: width + 'px', height: height + 'px', position: 'absolute', left: '-9999px'}"></canvas>
  </view>
</template>

<script>
import { ref, onMounted, computed } from 'vue';
import { createSliderCaptcha } from '@/sheep/helper/captcha';

export default {
  name: 's-slider-captcha',
  props: {
    // 画布宽度
    width: {
      type: Number,
      default: 280 // 减小默认宽度以适配移动端
    },
    // 画布高度
    height: {
      type: Number,
      default: 140 // 减小默认高度以适配移动端
    },
    // 滑块宽度
    sliderWidth: {
      type: Number,
      default: 44
    },
    // 滑块高度
    sliderHeight: {
      type: Number,
      default: 44
    },
    // 图片URL，用于自动生成验证码
    imageUrl: {
      type: String,
      default: ''
    },
    // 背景图URL，直接使用
    bgImage: {
      type: String,
      default: ''
    },
    // 滑块图URL，直接使用
    sliderImage: {
      type: String,
      default: ''
    },
    // 滑块Y坐标位置
    sliderY: {
      type: Number,
      default: 0
    },
    // 滑块X坐标位置（正确位置，用于验证）
    sliderX: {
      type: Number,
      default: 0
    },
    // 验证成功回调
    onSuccess: {
      type: Function,
      default: () => {}
    },
    // 验证失败回调
    onFail: {
      type: Function,
      default: () => {}
    },
    // 误差范围
    tolerance: {
      type: Number,
      default: 20
    },
    // 自动生成验证码
    autoGenerate: {
      type: Boolean,
      default: true
    },
    // 自定义Toast提示
    customToast: {
      type: Boolean,
      default: false
    }
  },
  setup(props, { emit }) {
    // 滑块验证码数据
    const captchaData = ref(null);
    
    // 滑块验证组件引用
    const puzzleVerifyRef = ref(null);
    
    // 组件是否已销毁
    const isDestroyed = ref(false);
    
    // 计算实际使用的尺寸（根据屏幕宽度自适应）
    const screenWidth = uni.getSystemInfoSync().screenWidth;
    const adaptedWidth = computed(() => {
      // 确保在小屏设备上不超过屏幕宽度的85%
      return Math.min(props.width, screenWidth * 0.85);
    });
    
    const adaptedHeight = computed(() => {
      // 保持与宽度相同的比例
      return Math.round(adaptedWidth.value / props.width * props.height);
    });
    
    // 安全地调用组件方法
    const safeCallMethod = (method, ...args) => {
      if (isDestroyed.value) {
        console.warn('组件已销毁，无法调用方法:', method);
        return false;
      }
      
      if (!puzzleVerifyRef.value) {
        console.warn('组件引用不存在，无法调用方法:', method);
        return false;
      }
      
      if (typeof puzzleVerifyRef.value[method] !== 'function') {
        console.warn('方法不存在:', method);
        return false;
      }
      
      try {
        puzzleVerifyRef.value[method](...args);
        return true;
      } catch (error) {
        console.error(`调用方法 ${method} 时出错:`, error);
        return false;
      }
    };
    
    // 生成滑块验证码
    const generateCaptcha = async () => {
      try {
        console.log('开始生成滑块验证码...');
        
        // 如果提供了直接的背景图和滑块图，则不需要生成
        if (props.bgImage && props.sliderImage) {
          console.log('使用直接提供的背景图和滑块图');
          captchaData.value = {
            bgImage: props.bgImage,
            sliderImage: props.sliderImage,
            position: { x: props.sliderX, y: props.sliderY },
            sliderDistance: props.sliderX
          };
          
          // 触发生成完成事件
          emit('generated', captchaData.value);
          return;
        }
        
        // 否则使用imageUrl生成验证码
        if (!props.imageUrl) {
          console.error('未提供imageUrl或bgImage+sliderImage');
          if (!props.customToast) {
            uni.showToast({
              title: '验证码配置错误',
              icon: 'none'
            });
          }
          emit('generate-fail', new Error('未提供imageUrl或bgImage+sliderImage'));
          return;
        }
        
        const config = {
          width: adaptedWidth.value,
          height: adaptedHeight.value,
          sliderWidth: props.sliderWidth,
          sliderHeight: props.sliderHeight,
          bgCanvasId: 'bgCanvas',
          sliderCanvasId: 'sliderCanvas',
          cutCanvasId: 'cutCanvas'
        };
        
        const result = await createSliderCaptcha(props.imageUrl, config);
        
        console.log('滑块验证码生成结果:', result);
        captchaData.value = result;
        
        // 触发生成完成事件
        emit('generated', result);
      } catch (error) {
        console.error('生成滑块验证码失败:', error);
        if (!props.customToast) {
          uni.showToast({
            title: '生成验证码失败',
            icon: 'none'
          });
        }
        // 触发生成失败事件
        emit('generate-fail', error);
      }
    };
    
    // 初始化验证
    const initVerify = (e) => {
      console.log('初始化验证:', e);
      // 如果还没有生成验证码，则生成
      if (!captchaData.value && props.autoGenerate && (props.imageUrl || (props.bgImage && props.sliderImage))) {
        // 延迟生成验证码，确保组件已完全初始化
        setTimeout(() => {
          if (!isDestroyed.value) {
            generateCaptcha();
          }
        }, 300);
      }
    };
    
    // 验证滑块
    const verifySlider = (e) => {
      console.log('验证滑块:', e);
      
      // 滑动距离
      const sliderDistance = e.slipDistance;
      // 正确位置
      let correctPosition = 0;
      
      if (captchaData.value) {
        correctPosition = captchaData.value.sliderDistance || captchaData.value.position.x;
      } else if (props.sliderX) {
        correctPosition = props.sliderX;
      }
      
      // 误差范围
      const tolerance = props.tolerance;
      
      console.log("正确位置:", correctPosition);
      console.log("滑动距离:", sliderDistance);
      
      if (Math.abs(sliderDistance - correctPosition) <= tolerance) {
        // 验证成功
        if (!props.customToast) {
          uni.showToast({
            title: '验证通过！',
            icon: 'success'
          });
        }
        
        // 调用成功回调
        props.onSuccess();
        
        // 触发成功事件
        emit('success');
        
        // 安全关闭验证
        setTimeout(() => {
          if (!isDestroyed.value) {
            safeCallMethod('closeVerify');
          }
        }, 500);
      } else {
        // 验证失败
        if (!props.customToast) {
          uni.showToast({
            title: '验证失败！',
            icon: 'none'
          });
        }
        
        // 调用失败回调
        props.onFail();
        
        // 触发失败事件
        emit('fail');
        
        // 安全重置验证
        if (!isDestroyed.value) {
          safeCallMethod('reset');
          // 重新生成验证码
          generateCaptcha();
        }
      }
    };
    
    // 显示验证
    const showVerify = () => {
      console.log('调用showVerify方法', puzzleVerifyRef.value);
      
      // 如果直接提供了背景图和滑块图但还没有生成验证码数据
      if (!captchaData.value && props.bgImage && props.sliderImage) {
        console.log('直接使用提供的背景图和滑块图');
        generateCaptcha().then(() => {
          console.log('生成验证码后显示验证组件');
          setTimeout(() => {
            safeCallMethod('show');
          }, 100);
        });
        return;
      }
      
      // 尝试显示验证组件
      if (!safeCallMethod('show')) {
        console.log('无法显示验证组件，尝试生成验证码');
        // 如果没有生成验证码，先生成
        if (!captchaData.value) {
          generateCaptcha().then(() => {
            console.log('生成验证码后再次尝试显示');
            setTimeout(() => {
              safeCallMethod('show');
            }, 100);
          }).catch(err => {
            console.error('生成验证码失败', err);
            if (!props.customToast) {
              uni.showToast({
                title: '验证码加载失败',
                icon: 'none'
              });
            }
          });
        } else {
          // 组件可能未初始化，延迟再试一次
          console.log('验证码已存在，延迟再试一次');
          setTimeout(() => {
            if (!safeCallMethod('show') && !props.customToast) {
              uni.showToast({
                title: '组件未初始化',
                icon: 'none'
              });
            }
          }, 300);
        }
      }
    };
    
    // 关闭验证
    const closeVerify = () => {
      safeCallMethod('closeVerify');
    };
    
    // 重置验证
    const resetVerify = () => {
      safeCallMethod('reset');
    };
    
    // 刷新验证码
    const refreshCaptcha = () => {
      generateCaptcha();
    };
    
    // 组件挂载后生成验证码
    onMounted(() => {
      isDestroyed.value = false;
      
      // 延迟生成验证码，确保组件已完全初始化
      if (props.autoGenerate && (props.imageUrl || (props.bgImage && props.sliderImage))) {
        setTimeout(() => {
          if (!isDestroyed.value) {
            generateCaptcha();
          }
        }, 500);
      }
    });
    
    // 组件销毁前
    const beforeUnmount = () => {
      console.log('滑块验证组件销毁');
      isDestroyed.value = true;
    };
    
    // 暴露方法给父组件
    return {
      captchaData,
      puzzleVerifyRef,
      initVerify,
      verifySlider,
      showVerify,
      closeVerify,
      resetVerify,
      refreshCaptcha,
      adaptedWidth,
      adaptedHeight,
      beforeUnmount
    };
  },
  beforeUnmount() {
    // 调用setup中的beforeUnmount方法
    if (this.beforeUnmount) {
      this.beforeUnmount();
    }
  }
}
</script>

<style lang="scss" scoped>
.s-slider-captcha {
  position: relative;
  width: 100%;
  /* 防止组件内容溢出 */
  overflow: hidden;
  z-index: 999;
}
</style> 